﻿using System.Text.RegularExpressions;

namespace Navigant.Common
{
    public static class EmailValidator
    {
        public static class Constants
        {
            /// <summary>
            /// Regular expression, which is used to validate an E-Mail address.
            /// </summary>
            public const string MatchEmailPattern =
                @"^(([^<>()[\]\\.,;:\s@""]+(\.[^<>()[\]\\.,;:\s@""]+)*)|("".+""))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$";

            public const string NullOrEmptyEmailAddressMessage = "The supplied email address was either null or an empty string.";
            public const string InvalidFormatEmailAddressMessage = "The email address was not in a valid format.";
        }
        
        /// <summary>
        /// Checks whether the given email address is valid.
        /// </summary>
        /// <param name="emailAddress"><see cref="System.String"/> that contains the e-mail address.</param>
        /// <returns>An <see cref="Navigant.Infrastructure.Helpers.EmailValidationResults"/> instance.</returns>
        public static EmailValidationResults ValidateEmailAddress(string emailAddress)
        {
            if (string.IsNullOrEmpty(emailAddress))
            {
                return new EmailValidationResults(EmailValidationResult.NullOrEmpty, 
                    Constants.NullOrEmptyEmailAddressMessage);
            }
            else
            {
                if (Regex.IsMatch(emailAddress, Constants.MatchEmailPattern))
                {
                    return new EmailValidationResults(EmailValidationResult.Valid, string.Empty);
                }
                else
                {
                    return new EmailValidationResults(EmailValidationResult.BadFormat,
                        Constants.InvalidFormatEmailAddressMessage);
                }
            }
        }
    }

    public enum EmailValidationResult
    {
        Valid,
        NullOrEmpty,
        BadFormat
    }

    public class EmailValidationResults
    {
        private EmailValidationResult result;
        private string details;

        public EmailValidationResults(EmailValidationResult result, string details)
        {
            this.result = result;
            this.details = details;
        }

        public EmailValidationResult Result
        {
            get { return this.result; }
        }

        public string Details
        {
            get { return this.details; }
        }

        #region Equality Tests

        /// <summary>
        /// Determines whether the specified entity is equal to the 
        /// current instance.
        /// </summary>
        /// <param name="entity">An <see cref="System.Object"/> that 
        /// will be compared to the current instance.</param>
        /// <returns>True if the passed in entity is equal to the 
        /// current instance.</returns>
        public override bool Equals(object result)
        {
            return result != null
                && result is EmailValidationResults
                && this == (EmailValidationResults)result;
        }

        /// <summary>
        /// Operator overload for determining equality.
        /// </summary>
        /// <param name="base1">The first instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <param name="base2">The second instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <returns>True if equal.</returns>
        public static bool operator ==(EmailValidationResults one,
            EmailValidationResults other)
        {
            // check for both null (cast to object or recursive loop)
            if ((object)one == null && (object)other == null)
            {
                return true;
            }

            // check for either of them == to null
            if ((object)one == null || (object)other == null)
            {
                return false;
            }

            if (one.result != other.result ||
                one.details != other.details)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Operator overload for determining inequality.
        /// </summary>
        /// <param name="base1">The first instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <param name="base2">The second instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <returns>True if not equal.</returns>
        public static bool operator !=(EmailValidationResults one,
            EmailValidationResults other)
        {
            return (!(one == other));
        }

        /// <summary>
        /// Serves as a hash function for this type.
        /// </summary>
        /// <returns>A hash code for the current Key 
        /// property.</returns>
        public override int GetHashCode()
        {
            return this.result.GetHashCode() ^
                this.details.GetHashCode();
        }

        #endregion
    }
}
